package com.platform.service;

import com.platform.dao.ApiPickupMapper;
import com.platform.entity.PickupVo;
import com.platform.entity.PointEntityVo;
import com.platform.util.CoordinateUtil;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class ApiPickupService {

    @Autowired
    ApiPickupMapper apiPickupMapper;

    /**
     * 根据用户经纬度，获取取货点信息
     * @param latitude 纬度
     * @param longitude 经度
     * @return
     */
    public List<PickupVo> getPickupList(String latitude, String longitude) {
        List<PickupVo> pickupVos = apiPickupMapper.findAll();
        if(pickupVos == null || pickupVos.isEmpty()){
            pickupVos = new ArrayList<>();
            return pickupVos;
        }
        //获取到了所有的地址，然后根据和前台传入的经纬度对比，按照距离远近排序
        List<PickupVo> handPickupVos = handPickup(latitude,longitude,pickupVos);
        return handPickupVos;
    }

    /**
     * 处理从数据库获取的取货点地址，根据用户经纬度，按照距离远近排序
     * @param latitude
     * @param longitude
     * @param pickupVos
     * @return
     */
    private List<PickupVo> handPickup(String latitude, String longitude,
                                      List<PickupVo> pickupVos) {
        List<PickupVo> handPickups = new ArrayList<>();
        PointEntityVo pointA = new PointEntityVo();
        pointA.setX(Double.valueOf(longitude));
        pointA.setY(Double.valueOf(latitude));

        String longitudeB = "";
        String latitudeB = "";
        //把距离存到scores里面，然后排序
//        double[] scores = new double[]{pickupVos.size()};
        ArrayList<Double> scores = new ArrayList<>();
        Map<Double,PickupVo> map = new HashedMap();

        for (int i = 0; i < pickupVos.size(); i++) {
            longitudeB = pickupVos.get(i).getLongitude();
            latitudeB = pickupVos.get(i).getLatitude();
            if(longitudeB == null || latitudeB == null ||
                    "".equals(longitudeB) || "".equals(latitudeB)){
                continue;
            }
            PointEntityVo pointB = new PointEntityVo();
            pointB.setX(Double.valueOf(longitudeB));
            pointB.setY(Double.valueOf(latitudeB));
            double distance = distanceToPoint(pointA, pointB);
            pickupVos.get(i).setDistance(distance+"");
            scores.add(distance);
            map.put(distance, pickupVos.get(i));
        }
        //排序
        Collections.sort(scores);
        for (int i = 0; i < scores.size(); i++) {
            handPickups.add(map.get(scores.get(i)));
        }
        return handPickups;
    }

    /**
     * 通过经纬度获取两点之间的距离
     * @param pointA
     * @param pointB
     * @return
     */
    private double distanceToPoint(PointEntityVo pointA,PointEntityVo pointB){
        //jts提供的几何要素工厂类
        GeometryFactory geometryFactory = new GeometryFactory();

        //火星坐标(gcj02)转GPS坐标(WGS84)
        double[] wgsPntA = CoordinateUtil.gcj02_To_Wgs84(pointA.x,pointA.y);
        double[] wgsPntB = CoordinateUtil.gcj02_To_Wgs84(pointB.x,pointB.y);

        //WGS84->高斯6度分带投影
        double[] gaussPntA = wgs84_To_Gauss6(wgsPntA[0],wgsPntA[1]);
        double[] gaussPntB = wgs84_To_Gauss6(wgsPntB[0],wgsPntB[1]);

        //通过几何要素工厂得到point实体
        Point pntA = geometryFactory.createPoint(new Coordinate(gaussPntA[0], gaussPntA[1]));
        Point pntB = geometryFactory.createPoint(new Coordinate(gaussPntB[0], gaussPntB[1]));
        // 两点距离
        return pntA.distance(pntB);
    }
    private double[] wgs84_To_Gauss6(double longitude, double latitude) {
        int ProjNo = 0;
        int ZoneWide; // //带宽
        double[] output = new double[2];
        double longitude1, latitude1, longitude0, X0, Y0, xval, yval;
        double a, f, e2, ee, NN, T, C, A, M, iPI;
        iPI = 0.0174532925199433; // //3.1415926535898/180.0;
        ZoneWide = 6; //6度带宽
        a = 6378137.0;
        f = 1.0 / 298.257223563; //WGS84坐标系参数
        //a = 6378245.0;f = 1.0 / 298.3; // 54年北京坐标系参数
        // //a=6378140.0; f=1/298.257; //80年西安坐标系参数
        ProjNo = (int) (longitude / ZoneWide);
        longitude0 = (double) (ProjNo * ZoneWide + ZoneWide / 2);
        longitude0 = longitude0 * iPI;
        longitude1 = longitude * iPI; // 经度转换为弧度
        latitude1 = latitude * iPI; // 纬度转换为弧度
        e2 = 2 * f - f * f;
        ee = e2 / (1.0 - e2);
        NN = a
                / Math.sqrt(1.0 - e2 * Math.sin(latitude1)
                * Math.sin(latitude1));
        T = Math.tan(latitude1) * Math.tan(latitude1);
        C = ee * Math.cos(latitude1) * Math.cos(latitude1);
        A = (longitude1 - longitude0) * Math.cos(latitude1);
        M = a
                * ((1 - e2 / 4 - 3 * e2 * e2 / 64 - 5 * e2 * e2 * e2 / 256)
                * latitude1
                - (3 * e2 / 8 + 3 * e2 * e2 / 32 + 45 * e2 * e2 * e2
                / 1024) * Math.sin(2 * latitude1)
                + (15 * e2 * e2 / 256 + 45 * e2 * e2 * e2 / 1024)
                * Math.sin(4 * latitude1) - (35 * e2 * e2 * e2 / 3072)
                * Math.sin(6 * latitude1));
        // 因为是以赤道为Y轴的，与我们南北为Y轴是相反的，所以xy与高斯投影的标准xy正好相反;
        xval = NN
                * (A + (1 - T + C) * A * A * A / 6 + (5 - 18 * T + T * T + 14
                * C - 58 * ee)
                * A * A * A * A * A / 120);
        yval = M
                + NN
                * Math.tan(latitude1)
                * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24 + (61
                - 58 * T + T * T + 270 * C - 330 * ee)
                * A * A * A * A * A * A / 720);
        X0 = 1000000L * (ProjNo + 1) + 500000L;
        Y0 = 0;
        xval = xval + X0;
        yval = yval + Y0;
        output[0] = xval;
        output[1] = yval;
        return output;
    }
}
